#include "dht11.h" // 包含DHT11库的头文件
#include "delay.h"

// 定义全局变量，用于存储湿度和温度的整数值以及小数部分
u8 humiInterget;
u8 tempInterget;
u8 humiDecimal;
u8 tempDecimal;

// 初始化DHT11数据接口为输出模式
void DHT11_IO_OUT(void)
{
    GPIO_InitTypeDef  GPIO_InitStructure; // 定义GPIO初始化结构体
    GPIO_InitStructure.GPIO_Pin = DHT11_IO; // 设置要初始化的GPIO引脚
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 设置为推挽输出模式
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 设置IO口速度为50MHz
    GPIO_Init(DHT11_PORT, &GPIO_InitStructure); // 根据初始化结构体配置GPIO
}

// 初始化DHT11数据接口为输入模式
void DHT11_IO_IN(void)
{
    GPIO_InitTypeDef  GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Pin = DHT11_IO;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; // 设置为浮空输入模式
    GPIO_Init(DHT11_PORT, &GPIO_InitStructure);
}

// 复位DHT11设备
void DHT11_RST(void)
{
    DHT11_IO_OUT(); // 设置IO为输出模式
    GPIO_ResetBits(DHT11_PORT,DHT11_IO); // 将IO置低
    delay_ms(20); // 延时20ms
    GPIO_SetBits(DHT11_PORT,DHT11_IO); // 将IO置高
    delay_us(30); // 微秒级延时
}

// 检查DHT11设备是否响应
u8 DHT11_Check(void)
{
    u8 retry = 0;
    DHT11_IO_IN(); // 设置IO为输入模式
    while ((GPIO_ReadInputDataBit(DHT11_PORT,DHT11_IO) == 1) && retry < 100)
    {
        retry++;
        delay_us(1);
    }
    if(retry >= 100) return 1; // 如果重试100次仍未检测到低电平，返回1表示错误
    else retry = 0;

    while ((GPIO_ReadInputDataBit(DHT11_PORT,DHT11_IO) == 0) && retry < 100)
    {
        retry++;
        delay_us(1);
    }
    if(retry >= 100) return 1; // 同上
    return 0; // 如果设备响应，则返回0表示成功
}

// 初始化DHT11设备
u8 DHT11_Init(void)
{
    RCC_APB2PeriphClockCmd(DHT11_RCC,ENABLE); // 使能DHT11的时钟
    DHT11_RST(); // 复位DHT11设备
    return DHT11_Check(); // 检查DHT11设备是否响应
}

// 读取DHT11设备的一位数据
u8 DHT11_Read_Bit(void)
{
    u8 retry = 0;
    while((GPIO_ReadInputDataBit(DHT11_PORT,DHT11_IO) == 1) && retry < 100)
    {
        retry++;
        delay_us(1);
    }
    retry = 0;
    while((GPIO_ReadInputDataBit(DHT11_PORT,DHT11_IO) == 0) && retry < 100)
    {
        retry++;
        delay_us(1);
    }
    delay_us(40); // 延时40微秒等待数据稳定
    return GPIO_ReadInputDataBit(DHT11_PORT,DHT11_IO); // 返回当前位的数据
}

// 读取DHT11设备的一个字节数据
u8 DHT11_Read_Byte(void)
{
    u8 i, dat = 0;
    for (i = 0; i < 8; i++)
    {
        dat <<= 1; // 左移当前数据，为新读取的位腾出位置
        dat |= DHT11_Read_Bit(); // 读取一位数据并合并
    }
    return dat;
}

// 读取DHT11设备的温度和湿度数据
u8 DHT11_Read_Data(u8 *humiInterget, u8 *tempInterget, u8 *humiDecimal, u8 *tempDecimal)
{
    u8 buf[5];
    u8 i;
    DHT11_RST(); // 复位DHT11设备
    if(DHT11_Check() == 0) // 如果设备响应
    {
        for(i = 0; i < 5; i++)
        {
            buf[i] = DHT11_Read_Byte(); // 读取5个字节的数据
        }
        if((buf[0] + buf[1] + buf[2] + buf[3]) == buf[4]) // 校验数据
        {
            *humiInterget = buf[0]; // 湿度整数部分
            *humiDecimal = buf[1]; // 湿度小数部分
            *tempInterget = buf[2]; // 温度整数部分
            *tempDecimal = buf[3]; // 温度小数部分
        }
        else return 1; // 如果数据校验失败，返回1表示错误
    }
    else return 1; // 如果设备未响应，返回1表示错误
    return 0; // 如果数据读取成功，返回0
}
